# ifndef _BBASE_H
# define _BBASE_H

# include<iostream>
# include<vector>
# include<algorithm>
# include"Function.h"


/**
* @brief 定义一个 B 样条基函数
* 
*/
class Bbasis : public Function
{
private:
    int deg = 0;                       // 次数
    int index = 0;                     // 下标
    const std::vector<double> * point; // 插值节点，下标超出部分，人为按照间隔 1 补充插值点

    // 根据下标返回插值节点的值
    double getpoint(const int & i) const
    {
        double s = 0;
        int n = (*point).size();
        if(i >= 0 && i < n)  s = (*point)[i];
        else if(i < 0)       s = (*point)[0] + 1.0 * i;
        else                 s = (*point)[n - 1] + 1.0 * i - 1.0 * n + 1;
        return s;
    }

public:
    // 初始化构造
    Bbasis() {};
    // 构造函数， index 从 0 算起
    Bbasis(const int & _deg, const int & _index,
           const std::vector<double> & _point):
        deg{_deg}, index{_index} {point = & _point;};

    // 重载操作符 (), 完成函数运算
    double operator() (const double & _x) const
    {
        int n = (*point).size();
        double output = 0;

        if(deg == 0)
        {
            if(_x > getpoint(index - 1) && _x <= getpoint(index))
                output = 1;
        }
        else
        {
            Bbasis B1(deg - 1, index, *point), B2(deg - 1, index + 1, *point);
            output = (_x - getpoint(index - 1)) / (getpoint(index + deg - 1) - getpoint(index - 1)) * B1(_x)
                    + (getpoint(index + deg) - _x) / (getpoint(index + deg) - getpoint(index)) * B2(_x);
        }
        return output;
    }

    // 求导运算
   double diff(const double & _x) const
    {
        double output = 0;
        if(deg > 0)
        {
            Bbasis B1(deg - 1, index, *point), B2(deg - 1, index + 1, *point);
            output = deg * B1(_x) / (getpoint(index + deg - 1) - getpoint(index - 1))
                     - deg * B2(_x) / (getpoint(index + deg) - getpoint(index));
        }
        return output;
    }

    // 二阶导运算
    double second_diff(const double & _x) const
    {
        double output = 0;
        if(deg > 1)
        {
            Bbasis B1(deg - 1, index, *point), B2(deg - 1, index + 1, *point);
            output = deg * B1.diff(_x) / (getpoint(index + deg - 1) - getpoint(index - 1))
                     - deg * B2.diff(_x) / (getpoint(index + deg) - getpoint(index));
        }
        return output;
    }

    // 获得下标
    int Getindex() const
    {
        return index;
    }
};


/**
* @brief 根据给定节点信息和次数构造的一组 B 样条基函数
* 
*/
class Bbase
{
private:
    std::vector<double> point; // 插值节点
    int deg = 0;               // 次数
    std::vector<Bbasis> basis; // 生成的基函数

    // 根据节点和次数生成基函数
    void ComputeBasis()
    {
        std::vector<Bbasis> b1;
        for(int i = 0; i < point.size() + deg - 1; i++)
        {
            Bbasis B(deg, i + 1 - deg, point);
            b1.push_back(B);
        }
        basis.swap(b1);
    }

public:
    // 初始化构造
    Bbase() {};
    // 构造函数
    Bbase(const int & _deg, const std::vector<double> & _point):
        deg{_deg}, point{_point}
    {
        std::sort(point.begin(), point.end());

        if(deg <= 0)
        {
            std::cout << "The degree is not correct." << std::endl;
            return;
        }

        ComputeBasis();
    }

    // 重载操作符 "="
    void operator= (Bbase && B)
    {
        if(B.deg == 0)
        {
            std::cout << "The degree is not correct." << std::endl;
            return;
        }

        deg = B.deg;
        std::vector<double> _point(B.point);
        point.swap(_point);

        ComputeBasis();
    }

    // R重载操作符 "="
    void operator= (Bbase & B)
    {
        if(B.deg == 0)
        {
            std::cout << "The degree is not correct." << std::endl;
            return;
        }

        deg = B.deg;
        point.assign(B.point.begin(), B.point.end());

        ComputeBasis();
    }

    // 根据给定下标和自变量 _x 计算对应下标基函数的运算值，下标从0开始计算
    double operator() (const int & index, const double & _x) const
    {
        int n = point.size();
        if(index >= 1 - deg && index < n)
        {
            return basis[index - 1 + deg](_x);
        }
        Bbasis B(deg, index, point);
        return B(_x);
    }
    
    // 根据给定下标和自变量 _x 计算对应下标基函数的导函数值
    double diff(const int & index, const double & _x) const
    {
        int n = point.size();
        if(index >= 1 - deg && index < n)
            return basis[index - 1 + deg].diff(_x);
        Bbasis B(deg, index, point);
        return B.diff(_x);
    }

    // 根据给定下标和自变量 _x 计算对应下标基函数的二阶导函数值
    double second_diff(const int & index, const double & _x) const
    {
        int n = point.size();
        if(index >= 1 - deg && index < n)
            return basis[index - 1 + deg].second_diff(_x);
        Bbasis B(deg, index, point);
        return B.second_diff(_x);
    }

    // 返回基函数个数
    int size() const
    {
        return basis.size();
    }

    // 获取次数
    int GetDeg() const
    {
        return deg;
    }
};

# else
// Do nothing.
# endif